在 Go 中,return
用於結束一個函式的執行並返回一個值(或多個值)。
在進入 return
前,我們簡單複習一下昨天的函示。
函式的目的在於包裝一段程式碼,讓他可以被重複利用。
而函式會經歷定義函式跟呼叫函式這兩個運用流程。
要怎麼結束函式?就是用前一章有提過的 return
。
基本語法:
return
這樣就可以結束函式了。
package main
import "fmt"
func showHello(){
fmt.Println("Hello")
fmt.Println("你好")
}
func main(){
showHello()
}
執行結果:
Hello
你好
main
函式呼叫 showHello
函式,印出 Hello
你好
,自然結束,跳回 main
函式。
當沒有寫 return 程式就會一步一步執行下去直到結束。
package main
import "fmt"
func showHello() {
fmt.Println("執行 return !!!")
return
fmt.Println("Hello")
fmt.Println("你好")
}
func main() {
showHello()
}
執行結果:
執行 return !!!
當 main 函式呼叫 showHello 函式,碰到 return 程式就會中斷跳回 main 函式,所以不會印出任何東西。
而且當你在編譯器寫這段程式時,會出現unreachable code
這個意思是指到達不了的程式,這是因為用了return
的關係,所以Hello
跟你好
都不會印出來。
package main
import "fmt"
func show (msg string){
if msg == "Hello"{
return
}
fmt.Println(msg)
}
func main(){
show("Hello")
show("你好")
}
執行結果:
你好
以上面的程式來看,就只會印出你好
。
昨天的章節有提到,函式不一定要有回傳值,但有時回傳值會非常好用。
基本語法:
func 函式名稱(參數列表)回傳值資料型態{
函式內部的程式碼
return 回傳值,須符合定義中的資料型態
}
要注意的一點,回傳值必須與回傳值資料型態相等。
package main
import "fmt"
// 可以做整數乘法的函式
func multiply(n1 int, n2 int) int{
var result int = n1 * n2
return result
}
// 呼叫函式,取得回傳值
func main (){
var x int = multiply(3, 4){
fmt,Println(x)
}
}
執行結果:
12
根據上面程式碼,解釋如下:
main
函式會去呼叫 multiply
函式並將引數帶入到 multiply
函式的參數內。multiply
函式計算完的 result
,會因為 return
而回傳到 main
函式中呼叫它的地方,也就是 x
。x
變數就會是剛剛 multiply
函式計算過後的結果。在 Go 中,支援一次定義多個回傳值,也可以用來快速地實作錯誤處理。
而定義好幾個回傳值的資料型態要用逗號隔開,一個蘿蔔一個坑。
同時,多個回傳值非常有用,特別是在處理錯誤時,它允許你返回一個正常的結果以及一個錯誤值,而不需要使用異常捕獲或其他複雜的錯誤處理機制。
基本語法:
func 函式名稱(參數列表)(資料型態,資料行態,.....){
函式內部的程式碼
return 回傳值, 回傳值, .....
}
package main
import "fmt"
func calc (a int, b int)(int, int){
return a+b, a-b
}
func main(){
sum,diff := calc(5, 2)
fmt.Println(sum)
fmt.Println(diff)
}
執行結果:
7
3
補充:
這邊有一個關於宣告變數的新用法,可以在:=
左邊放接收回傳值的變數,在這邊就是sum
,diff
,接著,用,
分開,就可以得到我們要的值。
Go 允許用一個等式一次宣告多個變數,範例如下:
package main
import "fmt"
func main(){
a, b := 3, 7
fmt.Println(a, b)
}
執行結果:
3 7
package main
import (
"fmt"
"errors"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
result := a / b
return result, nil
}
func main() {
quotient1, err := divide(10.0, 2.0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", quotient1)
}
quotient2, err = divide(10.0, 0.0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", quotient2)
}
}
執行結果:
Result: 5
Error: division by zero
根據上面程式碼,解釋如下:
main
函式會去呼叫 divide
函式並將引數分別帶入到函式的參數內。b
不等於 0
時,會將 a
及 b
相除的 result
,以及身為 error
要回傳的值 nil
,一起回傳給 main()
。b
等於 0
時,會因為if 判斷式的關係而 return (回傳) 給 main
函式 0
以及 division by zero
。Result: 5
及 Error: division by zero
。之前有提到 Go 宣告變數,該變數一定要使用到,不然就會報錯。
但是有時只要一個變數值,但又有兩個回傳值,這時該怎麼解決?
只要將不使用的值的變數設為 _
即可。
package main
import "fmt"
func calc(a int, b int) (int, int){
return a+b, a-b
}
func main(){
sum, _ := calc(5, 2)
fmt.Println(sum)
}
執行結果:
7
package main
import "fmt"
func add(n1 int, n2 int) int {
var result int = n1 + n2
fmt.Println(result)
return 10
}
func main(){
add(3, 4)
}
執行結果:
7
這時候就只會印出 7。
10 跑去哪了?
如果要印出 10,就要給一個變數讓它存放 return
的值。
package main
import "fmt"
func add(n1 int, n2 int) int {
var result int = n1 + n2
fmt.Println(result)
return 10
}
func main(){
var x int = add(3, 4)
fmt.Println(x)
}
執行結果:
7
10
讓我們回傳相加的結果:
package main
import "fmt"
func add(n1 int, n2 int) int {
var result int = n1 + n2
return result // 回傳 n1 n2 相加的結果
}
func main(){
var x int = add(3, 4)
fmt.Println(x)
}
執行結果:
7
那為什麼要回傳值?
說不定我們需要用到回傳值繼續做接下來的運算或操作。
所以利用剛剛的回傳值來繼續運算,如下:
package main
import "fmt"
func add(n1 int, n2 int) int {
var result int = n1 + n2
return result
}
func main(){
var x int = add(3, 4)
fmt.Println(x*10)
}
執行結果:
70
package main
import "fmt"
func test() (int, string) {
return 5, "Hello"
}
func main(){
var x int
var s string
x, s = test()
fmt.Println(x, s)
}
執行結果:
5 Hello
記住!!!!!
在定義回傳值的資料型態時,給 int 就要是 int,一個蘿蔔一個坑,不然會出錯。
Go 也可以為回傳值命名,這樣不僅增加了程式碼的可讀性也使函式更易於理解。
package main
import "fmt"
func calc (a int, b int)(sum int, diff int){
sum, diff = a+b, a-b
return
}
func main(){
sum, diff := calc(5, 2)
fmt.Println(sum)
fmt.Println(diff)
}
執行結果:
7
3
這樣寫也是可以:
package main
import "fmt"
func calc (a int, b int)(sum int, diff int){
sum, diff = a+b, a-b
return sum, diff
}
func main(){
sum, diff := calc(5, 2)
fmt.Println(sum)
fmt.Println(diff)
}
執行的結果都會是相同的。
執行結果:
7
3
關於 Return
有幾點需要注意:
package main
import "fmt"
func test(num int) int{
if num > 10 {
fmt.Println("num > 10")
return num
}
fmt.Println("num < 10")
return num
}
func main(){
test(100)
}
執行結果:
num > 10
當執行到第 6 行時,因觸發 return
,所以後面的程式就不會執行,所以就會跳回呼叫該函式的地方,也就是第 12 行。
另外,有回傳值的函式並沒有強制一定要去接收它。
在 Loop
有提到 scope
在迴圈內所宣告的變數並不可以在迴圈外使用,將這個概念套到函式上。
package main
import "fmt"
func test(num int){
fmt.Println("in test()", num)
}
func main(){
num := 10
test(100)
fmt.Println("in main()", num)
}
執行結果:
in test() 100
in main() 10
這兩個函式都有用到 num
這個變數,但是因為 scope
的關係,所以這兩個函式所宣告的變數完全不受到影響,所以在使用時只要顧慮該函式的 scope
即可。
在 Go 中,如果一個有回傳值的函式有明確的回傳型態,則必須在函式的最後使用 return 來返回一個該型態的值,否則會發生編譯錯誤。
package main
import "fmt"
func test(num int) int{
if num > 10 {
fmt.Println("num > 10")
return num
}
fmt.Println("num < 10")
}
func main(){
test(100)
}
執行結果:
missing return (exit status 1)
package main
import "fmt"
func test(num int) int{
if num > 10 {
fmt.Println("num > 10")
return num
}
fmt.Println("num < 10")
return
fmt.Println("after return")
}
func main(){
test(100)
}
執行結果:
missing return (exit status 1)
根據這兩個例子,可以看到當 return
沒有在最後,就會發生編譯錯誤,所以當這樣修正過後。
package main
import "fmt"
func test(num int) int{
if num > 10 {
fmt.Println("num > 10")
return num
}
fmt.Println("num < 10")
fmt.Println("before return")
return
}
func main(){
test(5)
}
執行結果:
num < 10
before return
在 Go 中,函式的擺放順序對於程式的正確性是沒有影響的。這是因為 Go 在編譯時會將整個程式的所有函式都收集起來,並且進行符號解析,然後再進行編譯。
即使在程式中先呼叫了一個還未定義的函式,只要這個函式在後面定義了,程式也是可以正常運行的。
將 scope
的例子改寫:
package main
import "fmt"
func main(){
num := 10
test(100)
fmt.Println("in main()", num)
}
func test(num int){
fmt.Println("in test()", num)
}
執行結果:
in test() 100
in main() 10
執行結果是一樣的。
今天關於 Return
講得蠻多的,以下重點整理一下:
scope
,並不會影響其他函式中所宣告的變數。return
參考資料: